package com.jweb.plugins.rpc.impl.handler.netty;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.io.File;
import java.lang.reflect.Method;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jweb.framework.bean.BeanHandle;
import com.jweb.plugins.rpc.bean.RpcRequest;
import com.jweb.plugins.rpc.bean.RpcResponse;
import com.jweb.plugins.rpc.bean.Service;

public class NettyHandler extends SimpleChannelInboundHandler<RpcRequest> {

	private static final Logger LOGGER = LoggerFactory.getLogger(NettyHandler.class);

	private final Map<String, Service> handler;

	public NettyHandler(Map<String, Service> handler) {
		this.handler = handler;
	}

	@Override
	public void channelRead0(final ChannelHandlerContext ctx, RpcRequest request) throws Exception {
		RpcResponse response = new RpcResponse();
		response.setRequestId(request.getRequestId());
		try {
			Object result = handle(request);
			response.setResult(result);
		} catch (Throwable t) {
			response.setError(t);
		}
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

	private Object handle(RpcRequest request) throws Throwable {
		String className = request.getClassName();
		Service ser = handler.get(className+File.separator+request.getServiceTypeName());

		Class<?> ifaceClass = ser.getIface();
		String methodName = request.getMethodName();
		Class<?>[] parameterTypes = request.getParameterTypes();
		Object[] parameters = request.getParameters();
		Object serviceBean = BeanHandle.getBean(ser.getImpl());

		Method method = ifaceClass.getMethod(methodName, parameterTypes);
		method.setAccessible(true);
		return method.invoke(serviceBean, parameters);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		LOGGER.error("server caught exception", cause);
		ctx.close();
	}

}